package com.sean.community.service;

import com.alibaba.fastjson.JSONObject;
import com.sean.community.dao.elasticsearch.DiscussPostRepository;
import com.sean.community.entity.DiscussPost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ElasticsearchService {
    private DiscussPostRepository discussPostRepository;
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    public void setDiscussPostRepository(DiscussPostRepository discussPostRepository) {
        this.discussPostRepository = discussPostRepository;
    }

    @Autowired
    @Qualifier("elasticsearchClient")
    public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) {
        this.restHighLevelClient = restHighLevelClient;
    }

    public void saveDiscussPost(DiscussPost discussPost){
        discussPostRepository.save(discussPost);
    }

    public void deleteDiscussPost(int id){
        discussPostRepository.deleteById(id);
    }

    public Map<String, Object> searchDiscussPost(String keyword, int current, int limit) throws IOException {
        //构建查询请求对象, 指定查询的索引名称
        SearchRequest searchRequest = new SearchRequest("discusspost");
        //创建 查询条件构建器
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(QueryBuilders.multiMatchQuery(keyword, "title", "content"))  // 查询字段匹配
                .sort(SortBuilders.fieldSort("type").order(SortOrder.DESC))         // 排序
                .sort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
                .sort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .from(current)                            // 分页
                .size(limit)
                .highlighter(new HighlightBuilder() // 高亮
                        .field("title")
                        .field("content")
                        .preTags("<em>")
                        .postTags("</em>")
                        .requireFieldMatch(false)
                );
        // 设置搜索请求的源
        searchRequest.source(searchSourceBuilder);
        // 调用 es 进行 查询
        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        // 处理结果
        List<DiscussPost> list = new ArrayList<>();
        SearchHit[] hits = response.getHits().getHits();
        for(SearchHit hit : hits){
            DiscussPost discussPost = JSONObject.parseObject(hit.getSourceAsString(), DiscussPost.class);
            // 高亮替换
            HighlightField titleField = hit.getHighlightFields().get("title");
            if (titleField != null) {
                // 只将第一个匹配词设置为高亮，例如，互联网寒冬互联网寒冬，只有第一个互联网寒冬为高亮
                discussPost.setTitle(titleField.getFragments()[0].toString());
            }
            HighlightField contentField = hit.getHighlightFields().get("content");
            if (contentField != null) {
                discussPost.setContent(contentField.getFragments()[0].toString());
            }
            list.add(discussPost);
        }
        // 封装查询结果
        Map<String, Object> map = new HashMap<>();
        map.put("searchResultList", list);
        map.put("searchResultCount", (int)response.getHits().getTotalHits().value);
        return map;
    }
}
